﻿#region Using directives

using System;
using System.Collections.Generic;
using System.Text;

#endregion

namespace Weazel.Badger.Vhdl.Types
{
  /// <summary>
  /// This class represent a set of types. A set does not include
  /// any duplicate elements.
  /// </summary>
  public class TypeSet : ICollection<Type>
  {
    /// <summary>
    /// List used to store the members of this set
    /// </summary>
    private List<Type> content = new List<Type>();

    /// <summary>
    /// Returns the number of types in this set
    /// </summary>
    /// <value>number of types in this set</value>
    public int Count
    {
      get
      {
        return content.Count;
      }
    }

    /// <summary>
    /// Indexer to access the members of this set
    /// </summary>
    /// <param name="index">Index</param>
    /// <returns>type at index position</returns>
    public Type this[int index]
    {
      get
      {
        return content[index];
      }
    }

    /// <summary>
    /// Returns true iff this set is empty
    /// </summary>
    /// <returns></returns>
    public bool IsEmpty()
    {
      return content.Count == 0;
    }

    /// <summary>
    /// Add a type to this type set
    /// </summary>
    /// <param name="type">Type to add</param>
    public void Add(Type type)
    {
      if (type.Equals(null))
        throw new NullReferenceException("Cannot add 'null' to TypeSet");

      if (!content.Contains(type))
        content.Add(type);
    }

    /// <summary>
    /// Add a range to types to this type set
    /// </summary>
    /// <param name="types">types to add</param>
    public void AddRange(Type[] types)
    {
      foreach (Type t in types)
        Add(t);
    }

    /// <summary>
    /// Remove a type from this type set
    /// </summary>
    /// <param name="type">Type to remove</param>
    /// <returns>true iff the type was in the set</returns>
    public bool Remove(Type type)
    {
      return content.Remove(type);
    }

    /// <summary>
    /// Clear this type set
    /// </summary>
    public void Clear()
    {
      content.Clear();
    }

    /// <summary>
    /// Required by the ICollection interface
    /// </summary>
    /// <value></value>
    public bool IsReadOnly
    {
      get
      {
        return false;
      }
    }

    /// <summary>
    /// Required by the ICollection interface
    /// </summary>
    /// <param name="target"></param>
    /// <param name="len"></param>
    public void CopyTo(Type[] target, int len)
    {
      content.CopyTo(target, len);
    }

    /// <summary>
    /// Test if a type is included in this type set
    /// </summary>
    /// <param name="type">Type to test</param>
    /// <returns>true iff the type is included in the set</returns>
    public bool Contains(Type type)
    {
			/*
			foreach (Type t in content)
				if (t == type && t.Width == type.Width)
					return true;
			 * */

      return content.Contains(type);

			//return false;
    }

    /// <summary>
    /// Test if a type with a specified typeid is included in this set
    /// </summary>
    /// <param name="type">TypeId to test</param>
    /// <returns>True iff the set included a type with the specified typeid</returns>
    public bool Contains(TypeId type)
    {
      foreach (Type t in content)
        if (t == type)
          return true;

      return false;
    }

    /// <summary>
    /// Test if the set contains any of a range of types
    /// </summary>
    /// <param name="types">types to test</param>
    /// <returns>True iff the set contains any of the specified types</returns>
    public bool ContainsAny(Type[] types)
    {
      foreach (Type type in types)
        if (content.Contains(type))
          return true;

      return false;
    }

    /// <summary>
    /// Test if the set contains any a type of a range of typeid's
    /// </summary>
    /// <param name="types">typeids to test</param>
    /// <returns>True iff the set contains any of the specified types</returns>
    public bool ContainsAny(TypeSet types)
    {
      foreach (Type type in types.content)
        if (content.Contains(type))
          return true;

      return false;
    }

    /// <summary>
    /// Merge this set with another (Performs a union)
    /// </summary>
    /// <param name="types">Union result</param>
    public void Merge(TypeSet types)
    {
      foreach (Type type in types.content)
        Add(type);
    }

    public TypeSet()
    {
    }

    public TypeSet(Type type)
    {
      Add(type);
    }

    public TypeSet(Type[] range)
    {
      AddRange(range);
    }

    /// <summary>
    /// Returns the content of this set as an array
    /// Required by the ICollection interface
    /// </summary>
    /// <returns>Members of this set as an array</returns>
    public Type[] ToArray()
    {
      return content.ToArray();
    }

    /// <summary>
    /// Required by the ICollection interface
    /// </summary>
    /// <returns></returns>
    public System.Collections.IEnumerator GetEnumerator()
    {
      return content.GetEnumerator();
    }

    IEnumerator<Type> IEnumerable<Type>.GetEnumerator()
    {
      return content.GetEnumerator();
    } 

    /// <summary>
    /// Returns a string representation of this typeset   
    /// </summary>
    /// <returns>string representation of this type set</returns>
    public override string ToString()
    {
      if (content.Count == 0)
        return "empty";

      string s = "";
      foreach (Type t in content)
        s += t.ToString() + " ";

      return s;
    }

    /// <summary>
    /// Returns the intersection between this 
    /// and another set of types.
    /// </summary>
    /// <param name="set">type set</param>
    /// <returns>intersection</returns>
    public TypeSet Intersection(TypeSet set)
    {
      TypeSet result = new TypeSet();

			foreach (Type t1 in content)		
				foreach (Type t2 in set)
				{
					if (t1 == t2 && t1.Width == t2.Width && !result.content.Contains(t1))
						result.Add(t1);
				}				
			

      return result;
    }
  }
}
